package cn.fufeiii.bt.common.config;

import cn.fufeiii.bt.common.code.CommonResultEnum;
import cn.fufeiii.bt.common.util.JsonUtil;
import cn.fufeiii.bt.common.util.result.CommonResult;
import cn.hutool.core.bean.BeanUtil;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorViewResolver;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.View;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.charset.StandardCharsets;
import java.util.Map;

/**
 * 统一 浏览器和API访问报错 返回的attributes字段
 * 目前已知404会走到BasicErrorController这里
 *
 * @author FuFei
 * @see org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController
 * @see org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration
 * @see org.springframework.boot.autoconfigure.web.servlet.error.DefaultErrorViewResolver
 * @see org.springframework.boot.web.servlet.error.DefaultErrorAttributes
 */
@Configuration
public class WebJsonErrorViewConfig {

    /**
     * 通用的错误属性
     */
    @Bean
    public DefaultErrorAttributes defaultErrorAttributes() {
        return new CommonErrorAttributes();
    }

    /**
     * JSON View
     * 浏览器访问发生错误，返回的是JSON格式
     * 配置{@literal server.error.whitelabel.enabled=true}启用
     */
    @Bean
    @ConditionalOnProperty(prefix = "server.error.whitelabel", name = "enabled", havingValue = "false", matchIfMissing = false)
    public ErrorViewResolver errorViewResolver() {
        return (request, status, errorAttributes) -> new ModelAndView(new JsonView(), errorAttributes);
    }

    /**
     * 兼容浏览器访问和API访问的响应信息字段
     */
    public static class CommonErrorAttributes extends DefaultErrorAttributes {

        @Override
        public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions attributeOptions) {
            // 先获取spring默认的返回内容（timestamp status error message path）五个值
            Map<String, Object> defaultErrorAttributes = super.getErrorAttributes(webRequest, attributeOptions);
            // 增加通用的返回信息（使用error的值覆盖了message的值），兼容API和View的输出
            defaultErrorAttributes.putAll(BeanUtil.beanToMap(CommonResult.fail(CommonResultEnum.REQUEST_ABNORMALITY.getCode(), String.valueOf(defaultErrorAttributes.get("error")))));
            return defaultErrorAttributes;
        }

    }

    /**
     * 此view响应为json数据
     * 用于代替默认的{@link org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration.StaticView}
     */
    public static class JsonView implements View {

        @Override
        public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
            // 此model是经过自己的ErrorAttributes处理过后的mode
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());
            response.getWriter().write(JsonUtil.toJson(model));
        }

    }
}
